package com.sikulifang.bank.simulation.util;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.db.Entity;
import cn.hutool.json.JSONUtil;
import com.sikulifang.bank.simulation.dto.MapValueDTO;
import com.spire.pdf.FileFormat;
import com.spire.pdf.PdfDocument;
import com.spire.pdf.PdfPageBase;
import com.spire.pdf.general.find.PdfTextFind;
import com.spire.pdf.general.find.PdfTextFindCollection;
import com.spire.pdf.graphics.PdfBrush;
import com.spire.pdf.graphics.PdfBrushes;
import com.spire.pdf.graphics.PdfCanvas;
import com.spire.pdf.graphics.PdfTrueTypeFont;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import java.awt.*;
import java.awt.geom.Rectangle2D;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.math.BigDecimal;
import java.text.NumberFormat;
import java.util.HashMap;
import java.util.Map;

/**
 * ClassName PdfUtil
 * Description PdfUtil
 *
 * @author Yat
 * Date 2023/6/2 17:31
 * version 1.0
 */
@Slf4j
public class PdfUtil {


    @SneakyThrows
    public static void main(String[] args) {
        String path = "D:\\Work\\银行文档\\中信\\中信接口测试日志\\111\\中信模板.pdf";

        String pdf = createPdf(getMap());
        System.out.println(pdf);
        System.out.println(JSONUtil.toJsonStr(getMap()));

    }

    /**
     * 获取需要替换的文本
     */
    public static Map<String, MapValueDTO> getMap(Entity entity) {
        HashMap<String, MapValueDTO> map = new HashMap<>();

        // 交易日期：2023-05-18 09:29:10
        String format = "";
        if (StrUtil.isNotBlank(entity.getStr("tran_date"))) {
            format = "交易日期：" + DateUtil.format(
                    DateUtil.parse(
                            entity.getStr("tran_date") + entity.get("tran_time", "")
                    ),
                    DatePattern.ISO8601_PATTERN
            );
        }
        map.put("TransactionDate", getInstance(format, 224.7001953125, 62.74838638305664));

        // 业务类型：代发工资
        String summary = entity.getStr("summary");
        if (StrUtil.isBlank(summary)) {
            summary = "";
        } else {
            summary = "业务类型：" + summary;
        }
        map.put(
                "BusinessType",
                getInstance(summary, 15.005355834960938, 62.74838638305664)
        );

        // 付款人名称：融捷投资控股集团有限公司
        String accountName = entity.getStr("account_name");
        map.put("PayerName", getInstance(accountName, 96.62448120117188, 78.97416687011719));

        // 付款人账号：8110901013200614183
        String accountNo = entity.getStr("account_no");
        map.put("PayerAccountNumber", getInstance(accountNo, 96.62448120117188, 101.48222351074219));

        // 付款人开户行名称：中信银行广州分行账务中心
        map.put(
                "PayerBankName",
                getInstance(entity.getStr("bank_name"), 96.62448120117188, 123.99021911621094)
        );

        // 付款人开户行号：744691
        map.put(
                "PayerBankNumber",
                getInstance(entity.getStr("bank_no"), 96.62448120117188, 146.49827575683594)
        );

        // 收款人名称：氖春搓脑
        map.put(
                "PayeeName",
                getInstance(entity.getStr("opp_account_name"), 359.0581359863281, 78.97416687011719)
        );
        // 收款人账号：7446910130900000001
        map.put(
                "PayeeAccountNumber",
                getInstance(entity.getStr("opp_account_no"), 359.058135986328, 101.48222351074219)
        );
        // 收款人开户行名称：中信银行广州分行账务中心
        map.put(
                "PayeeBankName",
                getInstance(entity.getStr("opp_bank_name"), 359.0581359863281, 123.99021911621094)
        );

        // 收款人开户行号：744691
        map.put(
                "PayeeBankNumber",
                getInstance(entity.getStr("opp_bank_no"), 359.0581359863281, 146.49827575683594)
        );

        // 金额：人民币贰元整RMB2.00
        String toAmount = convertToAmount(entity.getBigDecimal("money"));
        MapValueDTO money;
        if (StrUtil.isBlank(toAmount)) {
            money = getInstance("", 96.62448120117188, 169.37644958496094);
        } else {
            money = getInstance(
                    "人民币" + toAmount + "RMB" + entity.getBigDecimal("money"),
                    96.62448120117188, 169.37644958496094
            );

        }
        map.put("money", money);

        // 摘要或附言：工资奖金
        String postScript = entity.getStr("post_script");
        if (StrUtil.isNotBlank(postScript)) {
            postScript = "摘要或附言：" + postScript;
        } else if (StrUtil.isNotBlank(entity.getStr("summary"))) {
            postScript = "摘要或附言：" + entity.getStr("summary");
        } else {
            postScript = "";
        }

        map.put("SummaryOrPostscript",
                getInstance(postScript, 54.189334869384766, 192.2645721435547));
        // 核心流水号：SC030003968139
        String serialNo = entity.getStr("serial_no");
        if (StrUtil.isBlank(serialNo)) {
            serialNo = entity.getStr("batch_serial_no");
        }
        map.put("SerialNumber", getInstance(serialNo, 15, 386.87));

        return map;
    }

    /**
     * Description: 金额小写转大写
     * <p>
     * Date: 2023/6/5 14:50
     * <p>
     * // * @param money 小写金额
     *
     * @return 大写金额
     */
    public static String convertToAmount(BigDecimal money) {
        if (money == null) {
            return "";
        }
        String[] upNum = {"零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"};
        String[] danWei = {"元", "拾", "佰", "仟", "万", "拾", "佰", "仟", "亿", "拾", "佰", "仟"};
        // 取消科学记数法
        NumberFormat numFormat = NumberFormat.getInstance();
        // 设置小数位个数
        numFormat.setMaximumFractionDigits(2);
        // 取消科学技术发
        numFormat.setGroupingUsed(false);
        String formatNum = numFormat.format(money);
        // 用于存放上个参数的值
        String lastUpNum = "null";
        // 返回的结果
        String result = "";
        // 浮点型转为字符型
        String[] split = Convert.toStr(formatNum).split("\\.");
        String strMoney = split[0];
        String point;
        // 小数部分取值处理。
        if (split.length > 1) {
            point = split[1];
            if (point.length() == 1) {
                point = point.concat("0");
            }
        } else {
            point = "0";
        }
        // 大于12位就直接返回。
        int moneyLen = strMoney.length();
        if (money.compareTo(new BigDecimal("0")) == 0) {
            return "零元整";
        }
        if (moneyLen > 12) {
            log.error("金额：" + money + "元，超出大写转换范围。最大金额：999999999999.99元");
            return Convert.toStr(money);
        }
        // 整数(integer)部分处理。
        if (!"0".equals(strMoney)) {
            for (int i = 0; i < moneyLen; i++) {
                String strNum = strMoney.charAt(i) + "";
                int singleNum = Integer.parseInt(strNum);
                String upSingleNum = upNum[singleNum];
                // 上一为不等于0的情况
                if (!"零".equals(lastUpNum)) {
                    if (!"零".equals(upSingleNum)) {
                        result = result.concat(upSingleNum).concat(danWei[moneyLen - i - 1]);
                    } else
                        // 为零但是在万、亿位上要加单位 (moneyLen-i)==9 指的是单位：亿。  (moneyLen-i)==5指的是单位：万
                        if ((moneyLen - i) == 5 || (moneyLen - i) == 9) {
                            lastUpNum = "";
                        } else {
                            result = result.concat(upSingleNum);
                        }
                }
                // 上一位为0的情况
                if ("零".equals(lastUpNum) && !"零".equals(upSingleNum)) {
                    result = result.concat(upSingleNum).concat(danWei[moneyLen - i - 1]);
                }
                // 捕捉上一位数（lastUpNum）为零的情况做优化。
                if ((moneyLen - i) == 5 || (moneyLen - i) == 9) {
                    // 排除加单位时前面为"零"的情况。如：两百零万
                    if ("零".equals(lastUpNum) || "null".equals(lastUpNum)) {
                        result = result.substring(0, result.length() - 1);
                    }
                    if (!result.endsWith("亿")) {
                        result = result.concat(danWei[moneyLen - i - 1]);
                    }
                    lastUpNum = "";
                } else {
                    // 把当前大写数字复制给 lastUpNum 用于下次判断
                    lastUpNum = upSingleNum;
                }
            }
            // 对几万元整和几亿元整(result:五万零或者五亿零零)做优化。
            result = result.replaceAll("零零", "零");
            if (result.endsWith("零")) {
                result = result.substring(0, result.length() - 1);
            }
            result = result.concat("元");
            result = result.replaceAll("元元", "元");
            result = result.replaceAll("万万", "万");

        }

        // 小数(point)部分处理
        if ("0".equals(point)) {
            result = result + "整";
        } else {
            if ((point.charAt(0) + "").equals("0")) {
                result = result.concat(getIndexStr(upNum, point, 1, "分"));
            } else if ((point.charAt(1) + "").equals("0")) {
                result = result.concat(getIndexStr(upNum, point, 0, "角"));
            } else {
                result = result.concat(getIndexStr(upNum, point, 0, "角"))
                        .concat(getIndexStr(upNum, point, 1, "分"));

            }
        }

        return result;
    }

    private static String getIndexStr(String[] upNum, String point, int num, String unit) {
        String str = Convert.toStr(point.charAt(num));
        int index = Integer.parseInt(str);
        return upNum[index] + unit;
    }

    /**
     * 获取需要替换的文本
     */
    public static Map<String, MapValueDTO> getMap() {
        Entity entity = new Entity();

        // 交易日期：2023-05-18 09:29:10
        entity.put("tran_date", "2023-05-18 09:29:10");
        // 业务类型：代发工资
        entity.put("summary", "代发工资");

        // 付款人名称：融捷投资控股集团有限公司
        entity.put("account_name", "融捷投资控股集团有限公司");
        // 付款人账号：8110901013200614183
        entity.put("account_no", "8110901013200614183");
        // 付款人开户行名称：中信银行广州分行账务中心
        entity.put("bank_name", "中信银行广州分行账务中心");
        // 付款人开户行号：744691
        entity.put("bank_no", "744691");

        // 收款人名称：氖春搓脑
        entity.put("opp_account_name", "氖春搓脑");
        // 收款人账号：7446910130900000001
        entity.put("opp_account_no", "7446910130900000001");
        // 收款人开户行名称：中信银行广州分行账务中心
        entity.put("opp_bank_name", "中信银行广州分行账务中心");
        // 收款人开户行号：744691
        entity.put("opp_bank_no", "744691");

        // 金额：人民币贰元整RMB2.00
        entity.put("money", "人民币贰元整RMB2.00");
        // 摘要或附言：工资奖金
        entity.put("post_script", "代发工资");
        // 核心流水号：SC030003968139
        entity.put("batch_serial_no", "SC030003968139");

        return getMap(entity);
    }

    /**
     * Description: 根据参数修改PDF文件
     * <p>
     * Date: 2023/6/5 13:51
     *
     * @param map 修改的参数
     * @return {@link String} 新文件绝对路径
     */
    public static String createPdf(Map<String, MapValueDTO> map) {


        Font font = new Font("宋体", Font.BOLD, 12);
        Font font1 = new Font("宋体", Font.BOLD, 9);

        // 创建 PdfTrueTypeFont 类的对象以设置字体
        PdfTrueTypeFont typeFont = new PdfTrueTypeFont(font);
        PdfTrueTypeFont typeFont1 = new PdfTrueTypeFont(font1);

        // 字体颜色
        PdfBrush black = PdfBrushes.getBlack();

        // 创建 PdfDocument 类的对象
        PdfDocument doc = new PdfDocument();
        // 载入PDF文档
        doc.loadFromStream(FileCache.getInstance().getInputStream());
        // 获取文档的第一页
        PdfPageBase page = doc.getPages().get(0);

        for (String key : map.keySet()) {
            MapValueDTO mapValueDTO = map.get(key);

            String value = mapValueDTO.getValue();
            if (StrUtil.isBlank(value)) {
                value = "";
            }

            PdfTextFindCollection collection = page.findText(key, true);
            for (PdfTextFind find : collection.getFinds()) {
                // 获取文本在页面中的范围
                for (Rectangle2D textBound : find.getTextBounds()) {
                    if (textBound instanceof Rectangle2D.Float rec) {
                        PdfBrush white = PdfBrushes.getWhite();
                        PdfCanvas canvas = page.getCanvas();
                        canvas.drawRectangle(white, rec);
                        if (key.equals("BusinessType") || key.equals("TransactionDate")) {
                            canvas.drawString(value, typeFont1, black, rec.getX(), rec.getY() - 2);
                        } else {
                            canvas.drawString(value, typeFont, black, rec.getX(), rec.getY() - 3);
                        }

                    }
                }
            }
        }

        File file = FileUtil.createTempFile("sklf", ".pdf", new File("sklf"), Boolean.TRUE);
        String result = FileUtil.normalize(file.getPath());
        // 保存文档
        doc.saveToFile(result, FileFormat.PDF);

        return result;
    }


    /**
     * Description: 将文件转换成Byte数组
     * <p>
     * Date: 2023/6/5 13:41
     *
     * @param filePath 文件路径
     * @return {@link byte[]}
     */
    public static byte[] getBytesByFile(String filePath) {
        File file = new File(filePath);
        try (FileInputStream fis = new FileInputStream(file);
             ByteArrayOutputStream bos = new ByteArrayOutputStream(1000)
        ) {
            byte[] b = new byte[1000];
            int n;
            while ((n = fis.read(b)) != -1) {
                bos.write(b, 0, n);
            }
            fis.close();
            byte[] data = bos.toByteArray();
            bos.close();
            return data;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static MapValueDTO getInstance(String value, double x, double y) {
        return MapValueDTO.builder().value(value).x(x).y(y).build();
    }
}
